package uebung02;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class Matrixmultiplikation
{
  String monitor = "";
  boolean flag = false;
  static int[][] matrix1 = randomMatrix(50, 50);
  static int[][] resultMatrix;
  static CyclicBarrier barrier = new CyclicBarrier(2);
  static CyclicBarrier barrier2 = new CyclicBarrier(3);
  static long timeStart;
  static long timeEnd;
  
  class Multiply1 implements Runnable
  {
    public void run()
    {
      System.out.println("T1 starts calculating");
      for(int i = 0; i<50; i++)
        multiplyPart1(matrix1, matrix1);
      System.out.println("T1 done calculating");
      try
      {
        System.out.println("T1 betritt Barriere");
        barrier.await();
      }
      catch (InterruptedException e)
      {}
      catch (BrokenBarrierException e)
      {}
      timeEnd = System.currentTimeMillis();
      System.out.println("T1 Ende");
      System.out.println("Parallel-Time: "+(timeEnd-timeStart)/50.0+" msec");
      try
      {
        System.out.println("T1 betritt letzte Barriere");
        barrier2.await();
      }
      catch (InterruptedException e)
      {}
      catch (BrokenBarrierException e)
      {}

    }
  }

  class Multiply2 implements Runnable
  {
    public void run()
    {
      System.out.println("T2 starts calculating");
      for(int i = 0; i<50; i++)
        multiplyPart2(matrix1, matrix1);
      System.out.println("T2 done calculating");
      try
      {
        System.out.println("T2 betritt Barriere");
        barrier.await();
      }
      catch (InterruptedException e)
      {}
      catch (BrokenBarrierException e)
      {}

      
      try
      {
        System.out.println("T2 betritt letzte Barriere");
        barrier2.await();
      }
      catch (InterruptedException e)
      {}
      catch (BrokenBarrierException e)
      {}

      System.out.println("T2 Ende");
    }
  }
  
  public static void main(String[] args)
  {
    Matrixmultiplikation m = new Matrixmultiplikation();
    Multiply1 multiply1 = m.new Multiply1();
    Multiply2 multiply2 = m.new Multiply2();
    
    Thread t1 = new Thread(multiply1);
    Thread t2 = new Thread(multiply2);
    
    timeStart = System.currentTimeMillis();
    t1.start();
    t2.start();
    
    try
    {
      System.out.println("Main betritt letzte Barriere");
      barrier2.await();
    }
    catch (InterruptedException e)
    {}
    catch (BrokenBarrierException e)
    {}

    
    // Zeitmessung seriell
    long timeStart2 = System.currentTimeMillis();
    for(int i = 0; i<20; i++)
      multiply(matrix1, matrix1);
    long timeEnd2 = System.currentTimeMillis();
    System.out.println("Serial-Time: "+(timeEnd2-timeStart2)/50.0+" msec");
    
    System.out.println("Main-Method done");
  }
  
  public static int[][] multiply(int[][] matrix1, int[][] matrix2)
  {
    int[][] result = new int[matrix1.length][matrix2[0].length];
        
    int tempResult = 0;
    for(int i = 0; i<result.length; i++)
      for(int j = 0; j<result[i].length; j++)
      {
        for(int k = 0; k<matrix2.length; k++)
          tempResult += matrix1[i][k] * matrix2[k][j];
        result[i][j] = tempResult;
        tempResult = 0;
      }
    return result;
  }

  public static void multiplyPart1(int[][] matrix1, int[][] matrix2)
  {
    resultMatrix = new int[matrix1.length][matrix2[0].length];
    
    try
    {
      barrier.await();
    }
    catch (InterruptedException e)
    {}
    catch (BrokenBarrierException e)
    {}
    
    int tempResult = 0;
    for(int i = 0; i<resultMatrix.length-resultMatrix.length/2; i++)
      for(int j = 0; j<resultMatrix[i].length; j++)
      {
        for(int k = 0; k<matrix2.length; k++)
          tempResult += matrix1[i][k] * matrix2[k][j];
        resultMatrix[i][j] = tempResult;
        tempResult = 0;
      }
  }

  public static void multiplyPart2(int[][] matrix1, int[][] matrix2)
  {
    resultMatrix = new int[matrix1.length][matrix2[0].length];
    
    try
    {
      barrier.await();
    }
    catch (InterruptedException e)
    {}
    catch (BrokenBarrierException e)
    {}

    int tempResult = 0;
    for(int i = resultMatrix.length/2; i<resultMatrix.length; i++)
      for(int j = 0; j<resultMatrix[i].length; j++)
      {
        for(int k = 0; k<matrix2.length; k++)
          tempResult += matrix1[i][k] * matrix2[k][j];
        resultMatrix[i][j] = tempResult;
        tempResult = 0;
      }
  }

  public static int[][] randomMatrix(int lines, int columns)
  {
    int[][] matrix = new int[lines][columns];
    for(int i = 0; i<matrix.length; i++)
      for(int j = 0; j<matrix[i].length; j++)
        matrix[i][j] = (int)(Math.random()*10);
    return matrix;
  }
  
  public static void printMatrix(int[][] matrix)
  {
    for(int i = 0; i<matrix.length; i++)
    {
      for(int j = 0; j<matrix[i].length; j++)
        System.out.printf("%4d", matrix[i][j]);
      System.out.println();
    }
  }
}
